{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import scipy.sparse as sparse\n",
    "import numpy as np\n",
    "import random\n",
    "import implicit\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "from sklearn import metrics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "articles_df = pd.read_csv('shared_articles.csv')\n",
    "interactions_df = pd.read_csv('users_interactions.csv')\n",
    "articles_df.drop(['authorUserAgent', 'authorRegion', 'authorCountry'], axis=1, inplace=True)\n",
    "interactions_df.drop(['userAgent', 'userRegion', 'userCountry'], axis=1, inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>timestamp</th>\n",
       "      <th>eventType</th>\n",
       "      <th>contentId</th>\n",
       "      <th>authorPersonId</th>\n",
       "      <th>authorSessionId</th>\n",
       "      <th>contentType</th>\n",
       "      <th>url</th>\n",
       "      <th>title</th>\n",
       "      <th>text</th>\n",
       "      <th>lang</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1459192779</td>\n",
       "      <td>CONTENT REMOVED</td>\n",
       "      <td>-6451309518266745024</td>\n",
       "      <td>4340306774493623681</td>\n",
       "      <td>8940341205206233829</td>\n",
       "      <td>HTML</td>\n",
       "      <td>http://www.nytimes.com/2016/03/28/business/dea...</td>\n",
       "      <td>Ethereum, a Virtual Currency, Enables Transact...</td>\n",
       "      <td>All of this work is still very early. The firs...</td>\n",
       "      <td>en</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1459193988</td>\n",
       "      <td>CONTENT SHARED</td>\n",
       "      <td>-4110354420726924665</td>\n",
       "      <td>4340306774493623681</td>\n",
       "      <td>8940341205206233829</td>\n",
       "      <td>HTML</td>\n",
       "      <td>http://www.nytimes.com/2016/03/28/business/dea...</td>\n",
       "      <td>Ethereum, a Virtual Currency, Enables Transact...</td>\n",
       "      <td>All of this work is still very early. The firs...</td>\n",
       "      <td>en</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1459194146</td>\n",
       "      <td>CONTENT SHARED</td>\n",
       "      <td>-7292285110016212249</td>\n",
       "      <td>4340306774493623681</td>\n",
       "      <td>8940341205206233829</td>\n",
       "      <td>HTML</td>\n",
       "      <td>http://cointelegraph.com/news/bitcoin-future-w...</td>\n",
       "      <td>Bitcoin Future: When GBPcoin of Branson Wins O...</td>\n",
       "      <td>The alarm clock wakes me at 8:00 with stream o...</td>\n",
       "      <td>en</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    timestamp        eventType            contentId       authorPersonId  \\\n",
       "0  1459192779  CONTENT REMOVED -6451309518266745024  4340306774493623681   \n",
       "1  1459193988   CONTENT SHARED -4110354420726924665  4340306774493623681   \n",
       "2  1459194146   CONTENT SHARED -7292285110016212249  4340306774493623681   \n",
       "\n",
       "       authorSessionId contentType  \\\n",
       "0  8940341205206233829        HTML   \n",
       "1  8940341205206233829        HTML   \n",
       "2  8940341205206233829        HTML   \n",
       "\n",
       "                                                 url  \\\n",
       "0  http://www.nytimes.com/2016/03/28/business/dea...   \n",
       "1  http://www.nytimes.com/2016/03/28/business/dea...   \n",
       "2  http://cointelegraph.com/news/bitcoin-future-w...   \n",
       "\n",
       "                                               title  \\\n",
       "0  Ethereum, a Virtual Currency, Enables Transact...   \n",
       "1  Ethereum, a Virtual Currency, Enables Transact...   \n",
       "2  Bitcoin Future: When GBPcoin of Branson Wins O...   \n",
       "\n",
       "                                                text lang  \n",
       "0  All of this work is still very early. The firs...   en  \n",
       "1  All of this work is still very early. The firs...   en  \n",
       "2  The alarm clock wakes me at 8:00 with stream o...   en  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "articles_df.head(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "CONTENT SHARED     3047\n",
       "CONTENT REMOVED      75\n",
       "Name: eventType, dtype: int64"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "articles_df['eventType'].value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "articles_df = articles_df[articles_df['eventType'] == 'CONTENT SHARED']\n",
    "articles_df.drop('eventType', axis=1, inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Int64Index: 3047 entries, 1 to 3121\n",
      "Data columns (total 9 columns):\n",
      "timestamp          3047 non-null int64\n",
      "contentId          3047 non-null int64\n",
      "authorPersonId     3047 non-null int64\n",
      "authorSessionId    3047 non-null int64\n",
      "contentType        3047 non-null object\n",
      "url                3047 non-null object\n",
      "title              3047 non-null object\n",
      "text               3047 non-null object\n",
      "lang               3047 non-null object\n",
      "dtypes: int64(4), object(5)\n",
      "memory usage: 238.0+ KB\n"
     ]
    }
   ],
   "source": [
    "articles_df.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 72312 entries, 0 to 72311\n",
      "Data columns (total 5 columns):\n",
      "timestamp    72312 non-null int64\n",
      "eventType    72312 non-null object\n",
      "contentId    72312 non-null int64\n",
      "personId     72312 non-null int64\n",
      "sessionId    72312 non-null int64\n",
      "dtypes: int64(4), object(1)\n",
      "memory usage: 2.8+ MB\n"
     ]
    }
   ],
   "source": [
    "interactions_df.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.merge(interactions_df[['contentId','personId', 'eventType']], articles_df[['contentId', 'title']], how = 'inner', on = 'contentId')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>contentId</th>\n",
       "      <th>personId</th>\n",
       "      <th>eventType</th>\n",
       "      <th>title</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8845298781299428018</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8845298781299428018</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-108842214936804958</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-1443636648652872475</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-1443636648652872475</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-1443636648652872475</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8020832670974472349</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8020832670974472349</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-9009798162809551896</td>\n",
       "      <td>LIKE</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-9009798162809551896</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             contentId             personId eventType  \\\n",
       "0 -3499919498720038879 -8845298781299428018      VIEW   \n",
       "1 -3499919498720038879 -8845298781299428018      VIEW   \n",
       "2 -3499919498720038879  -108842214936804958      VIEW   \n",
       "3 -3499919498720038879 -1443636648652872475      VIEW   \n",
       "4 -3499919498720038879 -1443636648652872475      VIEW   \n",
       "5 -3499919498720038879 -1443636648652872475      VIEW   \n",
       "6 -3499919498720038879 -8020832670974472349      VIEW   \n",
       "7 -3499919498720038879 -8020832670974472349      VIEW   \n",
       "8 -3499919498720038879 -9009798162809551896      LIKE   \n",
       "9 -3499919498720038879 -9009798162809551896      VIEW   \n",
       "\n",
       "                                           title  \n",
       "0  Hiri wants to fix the workplace email problem  \n",
       "1  Hiri wants to fix the workplace email problem  \n",
       "2  Hiri wants to fix the workplace email problem  \n",
       "3  Hiri wants to fix the workplace email problem  \n",
       "4  Hiri wants to fix the workplace email problem  \n",
       "5  Hiri wants to fix the workplace email problem  \n",
       "6  Hiri wants to fix the workplace email problem  \n",
       "7  Hiri wants to fix the workplace email problem  \n",
       "8  Hiri wants to fix the workplace email problem  \n",
       "9  Hiri wants to fix the workplace email problem  "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Int64Index: 72269 entries, 0 to 72268\n",
      "Data columns (total 4 columns):\n",
      "contentId    72269 non-null int64\n",
      "personId     72269 non-null int64\n",
      "eventType    72269 non-null object\n",
      "title        72269 non-null object\n",
      "dtypes: int64(2), object(2)\n",
      "memory usage: 2.8+ MB\n"
     ]
    }
   ],
   "source": [
    "df.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "VIEW               61043\n",
       "LIKE                5745\n",
       "BOOKMARK            2463\n",
       "COMMENT CREATED     1611\n",
       "FOLLOW              1407\n",
       "Name: eventType, dtype: int64"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df['eventType'].value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "event_type_strength = {\n",
    "   'VIEW': 1.0,\n",
    "   'LIKE': 2.0, \n",
    "   'BOOKMARK': 3.0, \n",
    "   'FOLLOW': 4.0,\n",
    "   'COMMENT CREATED': 5.0,  \n",
    "}\n",
    "\n",
    "df['eventStrength'] = df['eventType'].apply(lambda x: event_type_strength[x])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>contentId</th>\n",
       "      <th>personId</th>\n",
       "      <th>eventType</th>\n",
       "      <th>title</th>\n",
       "      <th>eventStrength</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8845298781299428018</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8845298781299428018</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-108842214936804958</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-1443636648652872475</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-1443636648652872475</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-1443636648652872475</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8020832670974472349</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-8020832670974472349</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-9009798162809551896</td>\n",
       "      <td>LIKE</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>2.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>-3499919498720038879</td>\n",
       "      <td>-9009798162809551896</td>\n",
       "      <td>VIEW</td>\n",
       "      <td>Hiri wants to fix the workplace email problem</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             contentId             personId eventType  \\\n",
       "0 -3499919498720038879 -8845298781299428018      VIEW   \n",
       "1 -3499919498720038879 -8845298781299428018      VIEW   \n",
       "2 -3499919498720038879  -108842214936804958      VIEW   \n",
       "3 -3499919498720038879 -1443636648652872475      VIEW   \n",
       "4 -3499919498720038879 -1443636648652872475      VIEW   \n",
       "5 -3499919498720038879 -1443636648652872475      VIEW   \n",
       "6 -3499919498720038879 -8020832670974472349      VIEW   \n",
       "7 -3499919498720038879 -8020832670974472349      VIEW   \n",
       "8 -3499919498720038879 -9009798162809551896      LIKE   \n",
       "9 -3499919498720038879 -9009798162809551896      VIEW   \n",
       "\n",
       "                                           title  eventStrength  \n",
       "0  Hiri wants to fix the workplace email problem            1.0  \n",
       "1  Hiri wants to fix the workplace email problem            1.0  \n",
       "2  Hiri wants to fix the workplace email problem            1.0  \n",
       "3  Hiri wants to fix the workplace email problem            1.0  \n",
       "4  Hiri wants to fix the workplace email problem            1.0  \n",
       "5  Hiri wants to fix the workplace email problem            1.0  \n",
       "6  Hiri wants to fix the workplace email problem            1.0  \n",
       "7  Hiri wants to fix the workplace email problem            1.0  \n",
       "8  Hiri wants to fix the workplace email problem            2.0  \n",
       "9  Hiri wants to fix the workplace email problem            1.0  "
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = df.drop_duplicates()\n",
    "grouped_df = df.groupby(['personId', 'contentId', 'title']).sum().reset_index()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>personId</th>\n",
       "      <th>contentId</th>\n",
       "      <th>title</th>\n",
       "      <th>eventStrength</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>12560</th>\n",
       "      <td>-2979881261169775358</td>\n",
       "      <td>4102576381061107965</td>\n",
       "      <td>Facebook is open-sourcing its AI bot-building ...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9226</th>\n",
       "      <td>-4312494396888667550</td>\n",
       "      <td>6198232071580299480</td>\n",
       "      <td>Empresas intensificam operações de barter dian...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>26768</th>\n",
       "      <td>2833428826475063405</td>\n",
       "      <td>8413971365124666862</td>\n",
       "      <td>Building Chatbots with Node.js - Online Traini...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1245</th>\n",
       "      <td>-8853658195208337106</td>\n",
       "      <td>5313335392004163852</td>\n",
       "      <td>Salesforce Architect Journey</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>23381</th>\n",
       "      <td>1202287501580555390</td>\n",
       "      <td>6769852549722242790</td>\n",
       "      <td>Itaú vende carteira de vida para Prudential | ...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18205</th>\n",
       "      <td>-1032019229384696495</td>\n",
       "      <td>7467940062038388159</td>\n",
       "      <td>4 lessons we can learn from Denmark about happ...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24702</th>\n",
       "      <td>1895326251577378793</td>\n",
       "      <td>39554158227241538</td>\n",
       "      <td>Campus São Paulo: conheça a primeira turma do ...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>24257</th>\n",
       "      <td>1623838599684589103</td>\n",
       "      <td>8835339470389644264</td>\n",
       "      <td>Aplicativos do Android agora podem reagir com ...</td>\n",
       "      <td>4.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>27299</th>\n",
       "      <td>3009557673221751067</td>\n",
       "      <td>-559964548932224920</td>\n",
       "      <td>Jeff Seguros: SEGUROS E GAMES</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14170</th>\n",
       "      <td>-2511855597392146401</td>\n",
       "      <td>-6843047699859121724</td>\n",
       "      <td>Ganhe 6 meses de acesso ao Pluralsight, maior ...</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  personId            contentId  \\\n",
       "12560 -2979881261169775358  4102576381061107965   \n",
       "9226  -4312494396888667550  6198232071580299480   \n",
       "26768  2833428826475063405  8413971365124666862   \n",
       "1245  -8853658195208337106  5313335392004163852   \n",
       "23381  1202287501580555390  6769852549722242790   \n",
       "18205 -1032019229384696495  7467940062038388159   \n",
       "24702  1895326251577378793    39554158227241538   \n",
       "24257  1623838599684589103  8835339470389644264   \n",
       "27299  3009557673221751067  -559964548932224920   \n",
       "14170 -2511855597392146401 -6843047699859121724   \n",
       "\n",
       "                                                   title  eventStrength  \n",
       "12560  Facebook is open-sourcing its AI bot-building ...            1.0  \n",
       "9226   Empresas intensificam operações de barter dian...            1.0  \n",
       "26768  Building Chatbots with Node.js - Online Traini...            1.0  \n",
       "1245                        Salesforce Architect Journey            1.0  \n",
       "23381  Itaú vende carteira de vida para Prudential | ...            1.0  \n",
       "18205  4 lessons we can learn from Denmark about happ...            1.0  \n",
       "24702  Campus São Paulo: conheça a primeira turma do ...            1.0  \n",
       "24257  Aplicativos do Android agora podem reagir com ...            4.0  \n",
       "27299                      Jeff Seguros: SEGUROS E GAMES            1.0  \n",
       "14170  Ganhe 6 meses de acesso ao Pluralsight, maior ...            1.0  "
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_df.sample(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "personId           int64\n",
       "contentId          int64\n",
       "title             object\n",
       "eventStrength    float64\n",
       "dtype: object"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_df.dtypes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "grouped_df['title'] = grouped_df['title'].astype(\"category\")\n",
    "grouped_df['personId'] = grouped_df['personId'].astype(\"category\")\n",
    "grouped_df['contentId'] = grouped_df['contentId'].astype(\"category\")\n",
    "grouped_df['person_id'] = grouped_df['personId'].cat.codes\n",
    "grouped_df['content_id'] = grouped_df['contentId'].cat.codes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>personId</th>\n",
       "      <th>contentId</th>\n",
       "      <th>title</th>\n",
       "      <th>eventStrength</th>\n",
       "      <th>person_id</th>\n",
       "      <th>content_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-8949113594875411859</td>\n",
       "      <td>No Brasil, '25% dos celulares ainda são 'Burro...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>65</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-8377626164558006982</td>\n",
       "      <td>Bad Writing Is Destroying Your Company's Produ...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>159</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-8208801367848627943</td>\n",
       "      <td>Ray Kurzweil: The world isn't getting worse - ...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>187</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-8187220755213888616</td>\n",
       "      <td>Organizing for digital acceleration: Making a ...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>195</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-7423191370472335463</td>\n",
       "      <td>Espresso Intents: não é magia, é tecnologia! -...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>313</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-7331393944609614247</td>\n",
       "      <td>Here's proof that Google is getting serious ab...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>327</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-6872546942144599345</td>\n",
       "      <td>My experience with Google's Associate Android ...</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>385</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-6728844082024523434</td>\n",
       "      <td>Seniority</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>416</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-6590819806697898649</td>\n",
       "      <td>Listas com RecyclerView - Android Dev BR</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>442</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>-9223121837663643404</td>\n",
       "      <td>-6558712014192834002</td>\n",
       "      <td>Google's fair use victory is good for open source</td>\n",
       "      <td>1.0</td>\n",
       "      <td>0</td>\n",
       "      <td>450</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              personId            contentId  \\\n",
       "0 -9223121837663643404 -8949113594875411859   \n",
       "1 -9223121837663643404 -8377626164558006982   \n",
       "2 -9223121837663643404 -8208801367848627943   \n",
       "3 -9223121837663643404 -8187220755213888616   \n",
       "4 -9223121837663643404 -7423191370472335463   \n",
       "5 -9223121837663643404 -7331393944609614247   \n",
       "6 -9223121837663643404 -6872546942144599345   \n",
       "7 -9223121837663643404 -6728844082024523434   \n",
       "8 -9223121837663643404 -6590819806697898649   \n",
       "9 -9223121837663643404 -6558712014192834002   \n",
       "\n",
       "                                               title  eventStrength  \\\n",
       "0  No Brasil, '25% dos celulares ainda são 'Burro...            1.0   \n",
       "1  Bad Writing Is Destroying Your Company's Produ...            1.0   \n",
       "2  Ray Kurzweil: The world isn't getting worse - ...            1.0   \n",
       "3  Organizing for digital acceleration: Making a ...            1.0   \n",
       "4  Espresso Intents: não é magia, é tecnologia! -...            1.0   \n",
       "5  Here's proof that Google is getting serious ab...            1.0   \n",
       "6  My experience with Google's Associate Android ...            1.0   \n",
       "7                                          Seniority            1.0   \n",
       "8           Listas com RecyclerView - Android Dev BR            1.0   \n",
       "9  Google's fair use victory is good for open source            1.0   \n",
       "\n",
       "   person_id  content_id  \n",
       "0          0          65  \n",
       "1          0         159  \n",
       "2          0         187  \n",
       "3          0         195  \n",
       "4          0         313  \n",
       "5          0         327  \n",
       "6          0         385  \n",
       "7          0         416  \n",
       "8          0         442  \n",
       "9          0         450  "
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_df.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "sparse_content_person = sparse.csr_matrix((grouped_df['eventStrength'].astype(float), (grouped_df['content_id'], grouped_df['person_id'])))\n",
    "sparse_person_content = sparse.csr_matrix((grouped_df['eventStrength'].astype(float), (grouped_df['person_id'], grouped_df['content_id'])))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:OpenBLAS detected. Its highly recommend to set the environment variable 'export OPENBLAS_NUM_THREADS=1' to disable its internal multithreading\n"
     ]
    }
   ],
   "source": [
    "model = implicit.als.AlternatingLeastSquares(factors=20, regularization=0.1, iterations=50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 50.0/50 [00:03<00:00, 16.43it/s]\n"
     ]
    }
   ],
   "source": [
    "alpha = 15\n",
    "data = (sparse_content_person * alpha).astype('double')\n",
    "\n",
    "# Fit the model\n",
    "model.fit(data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "content_id = 450\n",
    "n_similar = 10\n",
    "\n",
    "person_vecs = model.user_factors\n",
    "content_vecs = model.item_factors\n",
    "\n",
    "content_norms = np.sqrt((content_vecs * content_vecs).sum(axis=1))\n",
    "\n",
    "scores = content_vecs.dot(content_vecs[content_id]) / content_norms\n",
    "top_idx = np.argpartition(scores, -n_similar)[-n_similar:]\n",
    "similar = sorted(zip(top_idx, scores[top_idx] / content_norms[content_id]), key=lambda x: -x[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Google's fair use victory is good for open source\n",
      "Up your DevOps chops with this online Kubernetes class\n",
      "Google's Cloud Dataflow stomps on Apache Spark in new benchmark tests\n",
      "Inside OpenAI, Elon Musk's Wild Plan to Set Artificial Intelligence Free\n",
      "Artificial Intelligence's White Guy Problem\n",
      "Building immutable entities into Google Cloud Datastore\n",
      "Google lags behind Amazon and Microsoft's cloud in one important area\n",
      "Tensorflow wins\n",
      "The 100 (TV Series 2014- )\n",
      "The Mobile Growth Stack: 2017 Edition - Mobile Growth Stack\n"
     ]
    }
   ],
   "source": [
    "for content in similar:\n",
    "    idx, score = content\n",
    "    print(grouped_df.title.loc[grouped_df.content_id == idx].iloc[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "def recommend(person_id, sparse_person_content, person_vecs, content_vecs, num_contents=10):\n",
    "    # Get the interactions scores from the sparse person content matrix\n",
    "    person_interactions = sparse_person_content[person_id,:].toarray()\n",
    "    # Add 1 to everything, so that articles with no interaction yet become equal to 1\n",
    "    person_interactions = person_interactions.reshape(-1) + 1\n",
    "    # Make articles already interacted zero\n",
    "    person_interactions[person_interactions > 1] = 0\n",
    "    # Get dot product of person vector and all content vectors\n",
    "    rec_vector = person_vecs[person_id,:].dot(content_vecs.T).toarray()\n",
    "    \n",
    "    # Scale this recommendation vector between 0 and 1\n",
    "    min_max = MinMaxScaler()\n",
    "    rec_vector_scaled = min_max.fit_transform(rec_vector.reshape(-1,1))[:,0]\n",
    "    # Content already interacted have their recommendation multiplied by zero\n",
    "    recommend_vector = person_interactions * rec_vector_scaled\n",
    "    # Sort the indices of the content into order of best recommendations\n",
    "    content_idx = np.argsort(recommend_vector)[::-1][:num_contents]\n",
    "    \n",
    "    # Start empty list to store titles and scores\n",
    "    titles = []\n",
    "    scores = []\n",
    "\n",
    "    for idx in content_idx:\n",
    "        # Append titles and scores to the list\n",
    "        titles.append(grouped_df.title.loc[grouped_df.content_id == idx].iloc[0])\n",
    "        scores.append(recommend_vector[idx])\n",
    "\n",
    "    recommendations = pd.DataFrame({'title': titles, 'score': scores})\n",
    "\n",
    "    return recommendations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                               title     score\n",
      "0  Custo do Erro - Cinco motivos para investir em...  1.000000\n",
      "1  'The Simpsons' celebrates 600 episodes with a ...  0.787331\n",
      "2  15 Interesting JavaScript and CSS Libraries fo...  0.786678\n",
      "3                            15 minutos sobre Docker  0.761076\n",
      "4       10 Modern Software Over-Engineering Mistakes  0.735395\n",
      "5  Ray Kurzweil: The world isn't getting worse - ...  0.723578\n",
      "6  Do You Suffer From Deployment Anxiety? - DZone...  0.714369\n",
      "7  BDD Best Practices and Guidelines - Testing Ex...  0.708275\n",
      "8                         How to Get a Job at Google  0.699211\n",
      "9  Novo workaholic trabalha, pratica esportes e t...  0.693468\n"
     ]
    }
   ],
   "source": [
    "# Get the trained person and content vectors. We convert them to csr matrices\n",
    "person_vecs = sparse.csr_matrix(model.user_factors)\n",
    "content_vecs = sparse.csr_matrix(model.item_factors)\n",
    "\n",
    "# Create recommendations for person with id 50\n",
    "person_id = 50\n",
    "\n",
    "recommendations = recommend(person_id, sparse_person_content, person_vecs, content_vecs)\n",
    "\n",
    "print(recommendations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>title</th>\n",
       "      <th>person_id</th>\n",
       "      <th>eventStrength</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1727</th>\n",
       "      <td>Acquia Engage 2016: Day One</td>\n",
       "      <td>50</td>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1791</th>\n",
       "      <td>Um bilhão de arquivos mostram quem vence a dis...</td>\n",
       "      <td>50</td>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1781</th>\n",
       "      <td>Acquia Engage Awards Finalists Announced</td>\n",
       "      <td>50</td>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1778</th>\n",
       "      <td>Sharing innovation with your competitors - Dri...</td>\n",
       "      <td>50</td>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1769</th>\n",
       "      <td>Don't document your code. Code your documentat...</td>\n",
       "      <td>50</td>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1747</th>\n",
       "      <td>Who sponsors Drupal development? | Dries Buytaert</td>\n",
       "      <td>50</td>\n",
       "      <td>3.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1768</th>\n",
       "      <td>Johnson &amp; Johnson comprará grupo suíço por US$...</td>\n",
       "      <td>50</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1767</th>\n",
       "      <td>Slack and Google announce partnership focused ...</td>\n",
       "      <td>50</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1770</th>\n",
       "      <td>Rating the English Proficiency of Countries an...</td>\n",
       "      <td>50</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1766</th>\n",
       "      <td>Infográfico: Algoritmos para Aprendizado de Má...</td>\n",
       "      <td>50</td>\n",
       "      <td>1.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                  title  person_id  \\\n",
       "1727                        Acquia Engage 2016: Day One         50   \n",
       "1791  Um bilhão de arquivos mostram quem vence a dis...         50   \n",
       "1781           Acquia Engage Awards Finalists Announced         50   \n",
       "1778  Sharing innovation with your competitors - Dri...         50   \n",
       "1769  Don't document your code. Code your documentat...         50   \n",
       "1747  Who sponsors Drupal development? | Dries Buytaert         50   \n",
       "1768  Johnson & Johnson comprará grupo suíço por US$...         50   \n",
       "1767  Slack and Google announce partnership focused ...         50   \n",
       "1770  Rating the English Proficiency of Countries an...         50   \n",
       "1766  Infográfico: Algoritmos para Aprendizado de Má...         50   \n",
       "\n",
       "      eventStrength  \n",
       "1727            3.0  \n",
       "1791            3.0  \n",
       "1781            3.0  \n",
       "1778            3.0  \n",
       "1769            3.0  \n",
       "1747            3.0  \n",
       "1768            1.0  \n",
       "1767            1.0  \n",
       "1770            1.0  \n",
       "1766            1.0  "
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_df.loc[grouped_df['person_id'] == 50].sort_values(by=['eventStrength'], ascending=False)[['title', 'person_id', 'eventStrength']].head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                               title     score\n",
      "0  Novo workaholic trabalha, pratica esportes e t...  0.860717\n",
      "1  Psicóloga de Harvard diz que as pessoas julgam...  0.823842\n",
      "2                   Livro: Retrospectivas Divertidas  0.795512\n",
      "3          Speeding up ReSharper (and Visual Studio)  0.747674\n",
      "4  Ser um bom líder depende de inúmeros fatores. ...  0.739460\n",
      "5  How to Improve 8 Major Problem Areas for Japan...  0.728652\n",
      "6           Drupal and ambitious digital experiences  0.719386\n",
      "7  Uber China will reportedly merge with archriva...  0.716243\n",
      "8  Life Coach vs. Therapist, Learn the Difference...  0.712579\n",
      "9  Como resolver conflitos no ambiente corporativ...  0.693622\n"
     ]
    }
   ],
   "source": [
    "person_id = 2\n",
    "\n",
    "recommendations = recommend(person_id, sparse_person_content, person_vecs, content_vecs)\n",
    "\n",
    "print(recommendations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>title</th>\n",
       "      <th>eventStrength</th>\n",
       "      <th>person_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>51</th>\n",
       "      <td>Former Google career coach shares a visual tri...</td>\n",
       "      <td>6.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>48</th>\n",
       "      <td>Request lesson : How and when to use はず(=hazu)...</td>\n",
       "      <td>3.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>49</th>\n",
       "      <td>Aposta na inovação</td>\n",
       "      <td>3.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50</th>\n",
       "      <td>The Algorithm March, Japan's Strangely Enterta...</td>\n",
       "      <td>3.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>54</th>\n",
       "      <td>Como são escrita as risadas em japonês? - Suki...</td>\n",
       "      <td>3.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>52</th>\n",
       "      <td>A minha viagem à Maternidade #tetodomundo</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>53</th>\n",
       "      <td>Learn Hiragana: The Ultimate Guide</td>\n",
       "      <td>1.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                title  eventStrength  \\\n",
       "51  Former Google career coach shares a visual tri...            6.0   \n",
       "48  Request lesson : How and when to use はず(=hazu)...            3.0   \n",
       "49                                 Aposta na inovação            3.0   \n",
       "50  The Algorithm March, Japan's Strangely Enterta...            3.0   \n",
       "54  Como são escrita as risadas em japonês? - Suki...            3.0   \n",
       "52          A minha viagem à Maternidade #tetodomundo            1.0   \n",
       "53                 Learn Hiragana: The Ultimate Guide            1.0   \n",
       "\n",
       "    person_id  \n",
       "51          2  \n",
       "48          2  \n",
       "49          2  \n",
       "50          2  \n",
       "54          2  \n",
       "52          2  \n",
       "53          2  "
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_df.loc[grouped_df['person_id'] == 2].sort_values(by=['eventStrength'], ascending=False)[['title', 'eventStrength', 'person_id']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                               title     score\n",
      "0  Former Google career coach shares a visual tri...  0.852350\n",
      "1  Conselho da SABMiller aceita proposta de compr...  0.845572\n",
      "2     Shopping em BH terá fazenda urbana de 2.700 m²  0.823218\n",
      "3  Como são escrita as risadas em japonês? - Suki...  0.815867\n",
      "4  Ganhe 6 meses de acesso ao Pluralsight, maior ...  0.807558\n",
      "5  Request lesson : How and when to use はず(=hazu)...  0.738024\n",
      "6  Top Asset Tracking Software: The 52 Best Tools...  0.731673\n",
      "7  Startups apostam em aplicativos que conectam f...  0.727742\n",
      "8  Revista MundoLogística - Sistema desenvolvido ...  0.719920\n",
      "9                    40 Basic Japanese conversations  0.716472\n"
     ]
    }
   ],
   "source": [
    "person_id = 1\n",
    "\n",
    "recommendations = recommend(person_id, sparse_person_content, person_vecs, content_vecs)\n",
    "\n",
    "print(recommendations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>title</th>\n",
       "      <th>eventStrength</th>\n",
       "      <th>person_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>44</th>\n",
       "      <td>Learn Hiragana: The Ultimate Guide</td>\n",
       "      <td>3.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>43</th>\n",
       "      <td>Firebase Test Lab for Android</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>45</th>\n",
       "      <td>Fresco, sim! - Android Dev BR</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>46</th>\n",
       "      <td>Japanese for dummies</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>47</th>\n",
       "      <td>Firebase and Google Cloud: better together</td>\n",
       "      <td>1.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                         title  eventStrength  person_id\n",
       "44          Learn Hiragana: The Ultimate Guide            3.0          1\n",
       "43               Firebase Test Lab for Android            1.0          1\n",
       "45               Fresco, sim! - Android Dev BR            1.0          1\n",
       "46                        Japanese for dummies            1.0          1\n",
       "47  Firebase and Google Cloud: better together            1.0          1"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grouped_df.loc[grouped_df['person_id'] == 1].sort_values(by=['eventStrength'], ascending=False)[['title', 'eventStrength', 'person_id']]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Evaluating the Recommender system"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "def make_train(ratings, pct_test = 0.2):\n",
    "    test_set = ratings.copy() # Make a copy of the original set to be the test set. \n",
    "    test_set[test_set != 0] = 1 # Store the test set as a binary preference matrix\n",
    "    \n",
    "    training_set = ratings.copy() # Make a copy of the original data we can alter as our training set. \n",
    "    \n",
    "    nonzero_inds = training_set.nonzero() # Find the indices in the ratings data where an interaction exists\n",
    "    nonzero_pairs = list(zip(nonzero_inds[0], nonzero_inds[1])) # Zip these pairs together of item,user index into list\n",
    "\n",
    "    \n",
    "    random.seed(0) # Set the random seed to zero for reproducibility\n",
    "    \n",
    "    num_samples = int(np.ceil(pct_test*len(nonzero_pairs))) # Round the number of samples needed to the nearest integer\n",
    "    samples = random.sample(nonzero_pairs, num_samples) # Sample a random number of item-user pairs without replacement\n",
    "\n",
    "    content_inds = [index[0] for index in samples] # Get the item row indices\n",
    "\n",
    "    person_inds = [index[1] for index in samples] # Get the user column indices\n",
    "\n",
    "    \n",
    "    training_set[content_inds, person_inds] = 0 # Assign all of the randomly chosen user-item pairs to zero\n",
    "    training_set.eliminate_zeros() # Get rid of zeros in sparse array storage after update to save space\n",
    "    \n",
    "    return training_set, test_set, list(set(person_inds))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "content_train, content_test, content_persons_altered = make_train(sparse_content_person, pct_test = 0.2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "def auc_score(predictions, test):\n",
    "    fpr, tpr, thresholds = metrics.roc_curve(test, predictions)\n",
    "    return metrics.auc(fpr, tpr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "def calc_mean_auc(training_set, altered_persons, predictions, test_set):\n",
    "    store_auc = [] # An empty list to store the AUC for each user that had an item removed from the training set\n",
    "    popularity_auc = [] # To store popular AUC scores\n",
    "    pop_contents = np.array(test_set.sum(axis = 1)).reshape(-1) # Get sum of item iteractions to find most popular\n",
    "    content_vecs = predictions[1]\n",
    "    for person in altered_persons: # Iterate through each user that had an item altered\n",
    "        training_column = training_set[:,person].toarray().reshape(-1) # Get the training set column\n",
    "        zero_inds = np.where(training_column == 0) # Find where the interaction had not yet occurred\n",
    "        \n",
    "        # Get the predicted values based on our user/item vectors\n",
    "        person_vec = predictions[0][person,:]\n",
    "        pred = person_vec.dot(content_vecs).toarray()[0,zero_inds].reshape(-1)\n",
    "        \n",
    "        # Get only the items that were originally zero\n",
    "        # Select all ratings from the MF prediction for this user that originally had no iteraction\n",
    "        actual = test_set[:,person].toarray()[zero_inds,0].reshape(-1)\n",
    "        \n",
    "        # Select the binarized yes/no interaction pairs from the original full data\n",
    "        # that align with the same pairs in training \n",
    "        pop = pop_contents[zero_inds] # Get the item popularity for our chosen items\n",
    "        \n",
    "        store_auc.append(auc_score(pred, actual)) # Calculate AUC for the given user and store\n",
    "        \n",
    "        popularity_auc.append(auc_score(pop, actual)) # Calculate AUC using most popular and score\n",
    "    # End users iteration\n",
    "    \n",
    "    return float('%.3f'%np.mean(store_auc)), float('%.3f'%np.mean(popularity_auc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.981, 0.819)"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "calc_mean_auc(content_train, content_persons_altered,\n",
    "              [person_vecs, content_vecs.T], content_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
